package cn.kevinkun.KevinkunChart;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Base64;

import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.SimpleEvent;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.SimpleProperty;
import com.google.appinventor.components.annotations.UsesAssets;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.Component;
import com.google.appinventor.components.runtime.ComponentContainer;
import com.google.appinventor.components.runtime.EventDispatcher;
import com.google.appinventor.components.runtime.HVArrangement;
import com.google.appinventor.components.runtime.util.YailList;

import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.view.ViewGroup;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import android.webkit.WebViewClient;

@DesignerComponent(version = 1, category = ComponentCategory.EXTENSION, description = "extension to show a chart in a layout. ", iconName = "aiwebres/chart.png", nonVisible = true, helpUrl = "www.kevinkun.cn/chart")
@SimpleObject(external = true)
@UsesAssets(fileNames = "chart.js,dark.html,dark.js,default.html,echarts.min.js,infographic.html,infographic.js,macarons.html,macarons.js,roma.html,roma.js,shine.html,shine.js,vintage.html,vintage.js,")
public class KevinkunChart extends AndroidNonvisibleComponent implements Component {
	Activity activity;
	Context context;
	WebView webView;

	String imagePath;
	private String js = "";
	private int theme = 1;
	private HVArrangement layout = null;
	private String[] themes = new String[] { "default", "dark", "macarons", "roma", "shine", "vintage", "infographic" };
	private String yAxisMin = "null";
	private boolean valueVisible = true;
	private boolean animation = false;

	public KevinkunChart(ComponentContainer container) {
		super(container.$form());
		this.activity = container.$context();
		this.context = container.$context();
	}

	WebViewClient webViewClient = new WebViewClient() {
		public void onPageFinished(WebView view, String url) {
			webView.evaluateJavascript("yAxisMin=" + yAxisMin + "; showValue=" + valueVisible + "; animation=" + animation + ";", null);
			runjs();
		}
	};

	@SimpleFunction(description = "layout: where the chart to be shown")
	public void Init(HVArrangement layout) {
		this.layout = layout;
		ViewGroup viewGroup = (ViewGroup) layout.getView();
		viewGroup.removeAllViews();
		this.webView = new WebView(this.activity);
		viewGroup.addView(this.webView);
	
	}
	
	private void showChart() {
		this.webView.setWebViewClient(this.webViewClient);
		this.webView.getSettings().setAllowFileAccess(true);
		this.webView.getSettings().setJavaScriptEnabled(true);
		this.webView.addJavascriptInterface(new JsObject(), "ECHARTS");

		try {
			this.webView.loadUrl(this.form.getAssetPathForExtension(this, themes[theme - 1] + ".html"));
		} catch (IOException localIOException) {
		}
	}

	@SimpleFunction(description = "legends: list; labels: list; datas: list of list")
	public void Bar(YailList legends, YailList labels, YailList datas) {

		js = "bar('" + "" + "'," + legends.toJSONString() + "," + labels.toJSONString() + "," + datas.toJSONString()
				+ ");";
		showChart();

	}

	@SimpleFunction(description = "legends: list; labels: list; datas: list of list")
	public void Line(YailList legends, YailList labels, YailList datas, boolean smooth) {

		js = "line('" + "" + "'," + legends.toJSONString() + "," + labels.toJSONString() + "," + datas.toJSONString()
				+ "," + smooth + ");";
		showChart();

	}

	@SimpleFunction(description = "labels: list; data: list; isRing: bollean")
	public void Pie(YailList labels, YailList data, boolean isRing) {

		js = "pie('" + "" + "'," + labels.toJSONString() + "," + data.toJSONString() + "," + isRing + ");";
		showChart();

	}

	@SimpleFunction(description = "")
	public void Gauge(int startAngle, int endAngle, int min, int max, float value) {

		js = "gauge(" + startAngle + "," + endAngle + "," + min + "," + max + "," + value + ");";
		showChart();

	}

	private void runjs() {
		webView.evaluateJavascript(js, null);
	}

	@SimpleFunction(description = "Save chart as image to ASD dir")
	public void SaveImage(String imageName) {

		this.imagePath = imageName;
		if (this.imagePath.startsWith("/")) {
			this.imagePath = this.imagePath.substring(1);
		}
		webView.evaluateJavascript("getDataURL();", null);

	}

	@SimpleEvent
	public void ImageSaved(String imagePath) {
		EventDispatcher.dispatchEvent(this, "ImageSaved", "file://" + imagePath);
	}

	@SimpleEvent
	public void Clicked(String legend, String label, String value) {
		EventDispatcher.dispatchEvent(this, "Clicked", new Object[] { legend, label, value });
	}

	@SimpleProperty(description = "theme = 1 default, 2 dark, 3 macarons, 4 roma, 5 shine, 6 vintage, 7 infographic,")
	public void ThemeIndex(int t) {
		if (t < 1) {
			t = 1;
		}
		if (t > 7) {
			t = 7;
		}
		theme = t;
		if (layout != null) {
			showChart();
		}
	}

	@SimpleProperty(description = "a number, or 'dataMin' or 'null'")
	public void YAxisMin(String s) {
		yAxisMin = s;
		showChart();
	}

	@SimpleProperty(description = "the number tip to be shown or not")
	public void ValueVisible(boolean b) {
		valueVisible = b;
		showChart();
	}

	@SimpleProperty(description = "animation is on or not")
	public void Animation(boolean b) {
		animation = b;
		showChart();
	}

	public boolean GenerateImage(String imgStr, String imgFilePath) {
		if (imgStr == null) {
			return false;
		}
		Base64.Decoder decoder = Base64.getDecoder();
		try {
			byte[] bytes = decoder.decode(imgStr);
			for (int i = 0; i < bytes.length; i++) {
				if (bytes[i] < 0) {
					bytes[i] = ((byte) (bytes[i] + 256));
				}
			}
			OutputStream out = new FileOutputStream(imgFilePath);
			out.write(bytes);
			out.flush();
			out.close();
			return true;
		} catch (Exception localException) {
		}
		return false;
	}

	private String asd() {
		String realpath = "";
		if (Build.VERSION.SDK_INT >= 29) {
			realpath = this.context.getExternalFilesDir(null).getPath();
		} else {
			realpath = this.context.getExternalFilesDir(null).getPath() + "/AppInventor";

		}
		return realpath;
	}

	private class JsObject {
		private JsObject() {
		}

		@JavascriptInterface
		public void getDataURL(String base64) {
			final String path = asd() + "/" + imagePath;
			base64 = base64.replace("data:image/png;base64,", "");
			boolean result = GenerateImage(base64, path);
			if (result) {
				activity.runOnUiThread(new Runnable() {
					public void run() {
						ImageSaved(path);
					}
				});
			}
		}

		@JavascriptInterface
		public void clicked(final String legend, final String label, final String value) {
			activity.runOnUiThread(new Runnable() {
				public void run() {
					Clicked(legend, label, value);
				}
			});
		}
	}
}
